/******************************************************************************
	This file is a part of the Snapshot Bioinformatics Project

	Copyright (C) 2012-2013 Jarom Schow

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "DmpParser.h"

#include <QtCore/QIODevice>

#include "GzFile.h"
#include "Progress.h"
#include "TaxonUpdateTree.h"

using namespace Bio;

const int	c_bufSize = 1024;
const int	c_maxTokens = 256;

/**
**/
DmpParser::DmpParser( const QString &fileType ) : m_fileType( fileType )
{
}

/**
**/
DmpParser::~DmpParser()
{
}

/**
**/
bool DmpParser::parse( QIODevice &dev )
{
	bool	status = true;
	char	*buffer = new char[c_bufSize];
	char	*tokens[c_maxTokens];

	const QIODevice	*sourceDev = &dev;

	if( const GzFile *gzFile = qobject_cast<const GzFile*>( sourceDev ) )
		sourceDev = gzFile->getSourceDevice();

	Progress	progress( QString( "Parsing %1 file..." ).arg( m_fileType ), int( sourceDev->size() ) );

	while( !dev.atEnd() ){
		if( dev.readLine( buffer, c_bufSize ) < 0 ){
			error( "Unable to read from device" );
			status = false;
			break;
		}

		progress.update( int( sourceDev->pos() ) );

		if( progress.isCanceled() ){
			status = false;
			break;
		}

		char	*curPos = buffer;
		int		curToken = 0;

		tokens[curToken++] = curPos; // start the first token

		while( *curPos != 0 ){
			if( curPos[0] == '\t' && curPos[1] == '|' && (curPos[2] == '\t' || curPos[2] == '\n') ){
				// end of token
				*curPos = 0;
				if( curPos[2] == '\n' )
					break; // end of line
				curPos += 3;
				tokens[curToken++] = curPos;
			}
			else
				curPos++;
		}

		if( !parseLine( tokens, curToken ) ){
			status = false;
			break;
		}
	}

	delete buffer;

	progress.finish();

	return status;
}

/**
**/
NodesDmpParser::NodesDmpParser( TaxonUpdateTree &tree ) : DmpParser( "Taxonomy Nodes" ), 
	m_tree( tree )
{
}

/**
**/
NodesDmpParser::~NodesDmpParser()
{
}

/**
**/
bool NodesDmpParser::parseLine( char **tokens, int count )
{
	if( count != 13 ){
		error( "Invalid data for nodes.dmp" );
		return false;
	}

	int		taxId = atoi( tokens[0] );
	int		parentId = atoi( tokens[1] );
	QString	rank = tokens[2];
	QString	emblCode = tokens[3];
	int		divisionId = atoi( tokens[4] );
	bool	inheritDivision = ( tokens[5][0] == '1' );
	int		genCodeId = atoi( tokens[6] );
	bool	inheritGenCode = ( tokens[7][0] == '1' );
	int		mitoGenCodeId = atoi( tokens[8] );
	bool	inheritMitoCode = ( tokens[9][0] == '1' );
	bool	genBankHidden = ( tokens[10][0] == '1' );
	bool	hiddenSubtree = ( tokens[11][0] == '1' );
	QString	comments = tokens[12];

	m_tree.insertNode( taxId, parentId, rank, genCodeId, mitoGenCodeId );

	return true;
}

/**
**/
NamesDmpParser::NamesDmpParser( TaxonUpdateTree &tree ) : DmpParser( "Taxonomy Names" ), 
	m_tree( tree )
{
}

/**
**/
NamesDmpParser::~NamesDmpParser()
{
}

/**
**/
bool NamesDmpParser::parseLine( char **tokens, int count )
{
	if( count != 4 ){
		error( "Invalid data for names.dmp" );
		return false;
	}

	int		taxId = atoi( tokens[0] );
	QString	name = tokens[1];
	QString	unique = tokens[2];
	QString	nClass = tokens[3];

	if( !unique.isEmpty() )
		name = unique;

	m_tree.insertName( taxId, name, nClass );

	return true;
}
